home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / pstopls.zoo / top.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-04  |  13.2 KB  |  567 lines

  1. /*
  2.  
  3.   ps.c: a program to print MiNT process statuses
  4.  
  5.   
  6.   Coded: 3/24/1991 by Tony Reynolds, cctony@sgisci1.ocis.olemiss.edu
  7.   For use with: MiNT release 0.7
  8.   Updated: 3/29/1991 by Eric Smith for MiNT version 0.8
  9.  
  10.   Updated and completely revised from 'ps' into 'top' by AKP 8/91.
  11.   Link with -lcurses and -ltermcap.  Beware!  Bammi's GNU curses
  12.   makefile actually links the termcap object files into curses.olb,
  13.   so changing them and recompiling only termcap.olb will have no effect!
  14.  
  15.   Updated some more 11/91 by Allan Pratt for MiNT version 0.9
  16. */
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <osbind.h>
  21. #include <errno.h>
  22. #include <basepage.h>
  23. #include <ioctl.h>
  24. #include <time.h>
  25. #include <curses.h>
  26. #include <signal.h>
  27. #include <mintbind.h>
  28. #include <ctype.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31.  
  32. #define MINWIDTH 36    /* this is the width of everything before the command */
  33. #define DEF_PTABSIZ 99    /* this is how many process' worth of table to have */
  34.  
  35. struct status {        /* defines values for internal->external process states */
  36.   int mint;        /* what MiNT knows */
  37.   char desc[6];        /* a textual description for above */
  38. } proc_stat[] = {
  39.   0,    "Run  ",    /* really "run" but "top" is always running! */
  40.   0x01, "Run  ",
  41.   0x20, "Wait ",
  42.   0x21, "Sleep",
  43.   0x22, "Exit ",
  44.   0x02, "TSR  ",
  45.   0x24, "Stop ",
  46.   -1,    "?????"
  47. };
  48.  
  49. typedef struct _context {
  50.     long    regs[15];    /* registers d0-d7, a0-a6 */
  51.     long    usp;        /* user stack pointer (a7) */
  52.     short    sr;        /* status register */
  53.     long    pc;        /* program counter */
  54.     long    ssp;        /* supervisor stack pointer */
  55.     long    term_vec;    /* GEMDOS terminate vector (0x102) */
  56.  
  57. /* these fields were added in MiNT 0.9 -- ERS */
  58.     char    fstate[216];    /* FPU internal state */
  59.     char    fregs[12*8];    /* registers fp0-fp7 */
  60.     long    fctrl[3];        /* FPCR/FPSR/FPIAR */
  61.     short    sfmt;            /* stack frame format identifier */
  62.     long    iar;            /* instruction address */
  63.     short    internal[4];    /* four words of internal info */
  64. } CONTEXT;
  65.  
  66. struct pinfo {
  67.     long     sysstack;
  68.     CONTEXT    ctxts[2];
  69.     long    magic;
  70.     char    *base;
  71.     short    pid, ppid, pgrp;
  72.     short    ruid, rgid;
  73.     short    euid, egid;
  74.     short    flags;
  75.     short    pri;
  76.     short    wait_q;
  77.     long    wait_cond;
  78.     unsigned long systime, usrtime, chldstime, chldutime;
  79.     unsigned long maxmem, maxdata, maxcore, maxcpu;
  80.     short    domain;
  81.     short    curpri;
  82. };
  83.  
  84. /* open the process named "name" */
  85. int
  86. open_proc(name)
  87. char *name;
  88. {
  89.   static char pname[32] = "u:\\proc\\";
  90.  
  91.   strcpy(pname+8, name);
  92.   return open(pname, 0);
  93. }
  94.  
  95. struct ptab {
  96.     short pid;
  97.     short used;
  98.     long lasttime;
  99.     char line[1];
  100. } *ptab;        /* an array of these gets malloc'ed */
  101.  
  102. #define INCPTAB(p) ((struct ptab *)(((char *)p) + sizeof(struct ptab) + width))
  103.  
  104. int garbage = 0;    /* when set, screen needs total update */
  105.  
  106. void
  107. quit(sig)
  108. long sig;
  109. {
  110.     /* move to bottom of screen */
  111.     mvcur(0, COLS - 1, LINES - 1, 0);
  112.     endwin();
  113.     exit(0);
  114. }
  115.  
  116. void
  117. usage()
  118. {
  119.     puts("Usage: top [-s sleeptime] [-w width] [-n nlines] [-r]");
  120.     puts("-r sorts procs in decreasing PID order; usually increasing PID.");
  121.     puts("TOP ONLY RUNS UNDER MiNT.  Use '?' to get help.");
  122.     exit(1);
  123. }
  124.  
  125. void
  126. dokill(s)
  127. char *s;
  128. {
  129.     int signum = SIGTERM;
  130.     int pid;
  131.     char *p;
  132.     char hold;
  133.  
  134.     while (isspace(*s)) s++;
  135.     if (*s == '-') {
  136.     p = ++s;
  137.     while (*p && !isspace(*p)) p++;
  138.     hold = *p;
  139.     *p = '\0';
  140.     if (p != s) signum = atoi(s);
  141.     *p = hold;
  142.     if (!signum) signum = SIGTERM;
  143.     s = p;
  144.     }
  145.     while (isspace(*s)) s++;
  146.  
  147.     while (*s) {
  148.     p = s;
  149.     while (*p && !isspace(*p)) p++;
  150.     hold = *p;
  151.     *p = '\0';
  152.     pid = atoi(s);
  153.     *p = hold;
  154.     s = p;
  155.     if (pid) (void)Pkill(pid,signum);
  156.     while (isspace(*s)) s++;
  157.     }
  158. }
  159.  
  160. void
  161. dorenice(s)
  162. char *s;
  163. {
  164.     int niceval;
  165.     int pid;
  166.     char *p;
  167.     char hold;
  168.  
  169.     while (isspace(*s)) s++;
  170.     p = s;
  171.     while (*p && !isspace(*p)) p++;
  172.     hold = *p;
  173.     *p = '\0';
  174.     niceval = atoi(s);
  175.     *p = hold;
  176.     s = p;
  177.  
  178.     while (isspace(*s)) s++;
  179.  
  180.     while (*s) {
  181.     p = s;
  182.     while (*p && !isspace(*p)) p++;
  183.     hold = *p;
  184.     *p = '\0';
  185.     pid = atoi(s);
  186.     *p = hold;
  187.     s = p;
  188.     if (pid) (void)Prenice(pid,niceval);
  189.     while (isspace(*s)) s++;
  190.     }
  191. }
  192.  
  193. int
  194. cmp_incr_pid(void *p1, void *p2)
  195. {
  196.     struct ptab *pt1 = p1, *pt2 = p2;
  197.     int pid1 = pt1->pid, pid2 = pt2->pid;
  198.     if (pid1 == -1 && pid2 == -1) return 0;
  199.     if (pid1 == -1) return 1;    /* send invalid procs to bottom */
  200.     if (pid2 == -1) return -1;
  201.     return pid1 - pid2;
  202. }
  203.  
  204. int
  205. cmp_decr_pid(void *p1, void *p2)
  206. {
  207.     struct ptab *pt1 = p1, *pt2 = p2;
  208.     int pid1 = pt1->pid, pid2 = pt2->pid;
  209.     if (pid1 == -1 && pid2 == -1) return 0;
  210.     if (pid1 == -1) return 1;    /* send invalid procs to bottom */
  211.     if (pid2 == -1) return -1;
  212.     return pid2 - pid1;
  213. }
  214.  
  215. char helpstr[] = 
  216.   "    s[leeptime] w[idth] n[lines] k[ill] r[enice] h[elp] p[riority] q[uit]\r";
  217.  
  218. void
  219. main(argc, argv)
  220. int argc;
  221. char **argv;
  222. {
  223.     int repeat_time = 0;
  224.     _DTA mydta;
  225.     int fd;
  226.     int fserror=0;
  227.     long place, procaddr;
  228.     int pid, ppid;
  229.     char *cmdline;
  230.     struct status *statp;
  231.     char bpage[sizeof(BASEPAGE)];
  232.     struct pinfo proc;
  233.     int thispid;
  234.     struct ptab *pt;
  235.     char *c;
  236.     unsigned long ptime, hour, min, sec, frac;
  237.     long realtime;
  238.     long lastclock = clock();
  239.     long thisclock;
  240.     int i;
  241.     long deltime;
  242.     int nprocs, nrunning;
  243.     long cummemory, idletime;
  244.     int width = 0;
  245.     long readfds;
  246.     char ibuf[80];
  247.     int ichar;
  248.     int taillen, cmdlen;
  249.     int tailstart;
  250.     int nlines = 0;
  251.     int helpline = 0;
  252.     int ptabsiz = DEF_PTABSIZ;
  253.     int len;
  254.     int (*cmpfunc)();
  255.     extern int __mint;
  256.     int ppid_mode = 1;
  257.  
  258.     cmpfunc = cmp_incr_pid;
  259.  
  260.     if (!__mint) usage();
  261.     --argc, ++argv;
  262.     while (argc) {
  263.     if (**argv != '-') usage();
  264.     switch(argv[0][1]) {
  265.         case 'r': cmpfunc = cmp_decr_pid;
  266.               break;
  267.         case 's': if (argc == 0) usage();
  268.               if ((repeat_time = atoi(argv[1])) == 0) usage();
  269.               ++argv, --argc;
  270.               break;
  271.         case 'w': if (argc == 0) usage();
  272.               if ((width = atoi(argv[1])) <= 0) usage();
  273.               if (width < MINWIDTH) width = MINWIDTH;
  274.               ++argv, --argc;
  275.               break;
  276.         case 'n': if (argc == 0) usage();
  277.               if ((nlines = atoi(argv[1])) <= 0) usage();
  278.               ++argv, --argc;
  279.               break;
  280.  
  281.         default: usage();
  282.     }
  283.     --argc, ++argv;
  284.     }
  285.  
  286.     Fsetdta(&mydta);          /* give the OS my new DTA */
  287.  
  288.     initscr();
  289.  
  290.     if (!width) width = COLS-1;    /* default if it's unset */
  291.     if (!repeat_time) repeat_time = 5;
  292.     if (LINES < 4) {
  293.     puts("top: can't run on a screen with < 4 lines");
  294.     exit(1);
  295.     }
  296.     if (nlines == 0 || nlines > (LINES-3)) nlines = LINES-3;
  297.  
  298.     /* struct ptab ends with char line[1] so there's already padding for '\0' */
  299.     if ((ptab = malloc((sizeof(struct ptab) + width) * ptabsiz)) == NULL) {
  300.     puts("top: can't get memory for process structures");
  301.     exit(1);
  302.     }
  303.  
  304.     cbreak();
  305.     noecho();
  306.  
  307.     signal(SIGINT,quit);
  308.     signal(SIGQUIT,quit);
  309.     signal(SIGHUP,quit);
  310.     signal(SIGTERM,quit);
  311.  
  312.     for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
  313.     pt->pid = -1;
  314.     pt->used = 0;
  315.     }
  316.  
  317.     while (1) {
  318.     fserror=Fsfirst("u:\\proc\\*.*", -1);
  319.     if (fserror < 0) {
  320.         fprintf(stderr, "ps: cannot list processes ?!");
  321.         exit(1);
  322.     }
  323.  
  324.     erase();
  325.  
  326.     /* top line is printed later */
  327.  
  328.     if (ppid_mode) {
  329.         printw("\n\nPID PPID STATUS   SIZE   TIME     %% COMMAND\n");
  330.     }
  331.     else {
  332.         printw("\n\nPID PRI CUR STATUS   SIZE   TIME     %% COMMAND\n");
  333.     }
  334.  
  335.     nprocs = 0;
  336.     nrunning = 0;
  337.     idletime = 0;
  338.     cummemory = 0;
  339.  
  340.     thisclock = clock();
  341.     realtime = (thisclock - lastclock) * (1000/CLOCKS_PER_SEC);
  342.     lastclock = thisclock;
  343.  
  344.     /* okay, now run the Fsnext bit through the wringer */
  345.  
  346.     fserror = E_OK;       /* set up for the loop */
  347.  
  348.     while (fserror == E_OK ) {
  349.         fd = open_proc(mydta.dta_name);
  350.         if (fd < 0) goto getnext;
  351.  
  352.         /* cut name off at '.' */
  353.         for (cmdline = mydta.dta_name;
  354.         *cmdline && *cmdline != '.';
  355.         cmdline++)
  356.             /* do nothing */ ;
  357.         *cmdline = 0;
  358.  
  359.         ioctl(fd, PPROCADDR, &procaddr);
  360.         lseek(fd, procaddr, 0);
  361.         read(fd, &proc, sizeof(proc));
  362.         pid = proc.pid;
  363.         ppid = proc.ppid;
  364.         ioctl(fd, PBASEADDR, &place);
  365.         lseek(fd, place, 0);
  366.         read(fd, bpage, sizeof(bpage));
  367.         close(fd);
  368.         cmdline = bpage+128;
  369.         if (*cmdline) *cmdline = ' ';
  370.  
  371.         /* span cmdline turning control chars into question marks */
  372.         for (c = cmdline; *c; c++) if (*c < ' ') *c = '?';
  373.  
  374.         taillen = c - cmdline;
  375.  
  376.         thispid = proc.pid;
  377.         if (ppid < 0) ppid = 0;
  378.  
  379.         statp = proc_stat;      /* hunt down string referring to
  380.                     process status */
  381.         while (statp->mint != mydta.dta_attribute &&
  382.         statp->mint >= 0) statp++;
  383.  
  384.         ptime = proc.systime + proc.usrtime;
  385.  
  386.         /* set deltime to the time used since last time we checked */
  387.         for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
  388.         if (pt->pid == thispid) {
  389.             pt->used = 1;
  390.             deltime = ptime - pt->lasttime;
  391.             pt->lasttime = ptime;
  392.             goto found;
  393.         }
  394.         }
  395.  
  396.         /* fell out: didn't find the process */
  397.         for (i = ptabsiz, pt = ptab; i; i--, pt = INCPTAB(pt)) {
  398.         if (pt->pid == -1) {
  399.             /* use this slot */
  400.             pt->used = 1;
  401.             pt->pid = thispid;
  402.             pt->lasttime = ptime;
  403.             deltime = (ptime > realtime ? realtime : ptime);
  404.             goto found;
  405.         }
  406.         }
  407.         /* fell out again - can't keep track of this process (sorry!) */
  408.         deltime = 0;
  409.         pt = NULL;
  410.  
  411. found:
  412.  
  413.         if (thispid == 0) {
  414.         /* idle time is charged to process zero */
  415.         idletime = deltime;
  416.         strcpy(mydta.dta_name,"(idle)");
  417.         }
  418.  
  419.         hour = (ptime/1000/60/60);
  420.         min = (ptime/1000/60)%60;
  421.         sec = (ptime/1000)%60;
  422.         frac = (ptime%1000) / 10;    /* (never anything in .001 digit) */
  423.  
  424.         if (ppid_mode) {
  425.         len = sprintf(pt->line,"%03d %03d %-5s %8ld ",
  426.             pid, ppid, statp->desc, mydta.dta_size);
  427.         }
  428.         else {
  429.         len = sprintf(pt->line,"%03d %3d %3d %-5s %8ld ",
  430.             pid, proc.pri, proc.curpri, statp->desc, mydta.dta_size);
  431.         }
  432.  
  433.         if (hour)
  434.         len += sprintf(pt->line + len,"%2ld:%02ld:%02ld",hour,min,sec);
  435.         else
  436.         len += sprintf(pt->line + len,"%2ld:%02ld.%02ld",min,sec,frac);
  437.  
  438.         len += sprintf(pt->line + len," %3ld ",(deltime * 100) / realtime);
  439.  
  440.         /* if the line's too long, cut off the tail so the total is width */
  441.         cmdlen = strlen(mydta.dta_name);
  442.         tailstart = len+cmdlen;
  443.         if (width < tailstart) cmdline[0] = 0;
  444.         else if (tailstart+taillen > width) {
  445.         cmdline[width-tailstart] = '\0';
  446.         }
  447.         sprintf(pt->line + len,"%s%s",mydta.dta_name,cmdline);
  448.  
  449.         nprocs++;
  450.  
  451.         cummemory += mydta.dta_size;
  452.         if (deltime) nrunning++;
  453.  
  454. getnext:
  455.         fserror = Fsnext();
  456.     }
  457.  
  458.     /*
  459.     * Now zero out those slots which weren't used in the last pass, and zero
  460.     * all "used" fields
  461.     */
  462.     for (i = nlines, pt = ptab; i; i--, pt = INCPTAB(pt)) {
  463.         if (!pt->used) pt->pid = -1;
  464.         else pt->used = 0;
  465.     }
  466.  
  467.     /*
  468.     * Now all processes are in the ptab array, their lines stored. Sort them
  469.     * into printing order and print nlines of them.
  470.     */
  471.  
  472.     qsort(ptab,nlines,sizeof(struct ptab) + width,cmpfunc);
  473.     if (nprocs < nlines) i = nprocs;
  474.     else i = nlines;
  475.     for (pt = ptab; i; i--, pt = INCPTAB(pt)) {
  476.         printw("%s\n",pt->line);
  477.     }
  478.  
  479.     /* compute idle percentage into idletime */
  480.     idletime = (idletime * 100) / realtime;
  481.  
  482.     move(0,0);
  483.     printw("Sample time: %5ld; %3ld%% idle; %3d processes, %3d running"
  484.         "; %ld bytes used\n",
  485.         realtime,idletime,nprocs,nrunning,cummemory);
  486.  
  487.     if (helpline) printw(helpstr);
  488.  
  489.     if (garbage) wrefresh(curscr);
  490.     else refresh();
  491.     garbage = 0;
  492.  
  493.     /* Fall asleep for repeat_time seconds or until a key comes in. */
  494.     /* We want zero to mean "no time" not "forever" so add one. */
  495.     readfds = 1;
  496.     if (Fselect(repeat_time * 1000 + 1,&readfds,0L,0L)) {
  497.         /* input waiting */
  498.         if (helpline) {
  499.         clrtoeol();
  500.         refresh();
  501.         helpline = 0;
  502.         }
  503.         ichar = getch();
  504.         switch(ichar) {
  505.         case 'L'-'@': 
  506.             garbage = 1;
  507.             break;
  508.         case 's':
  509.             printw("sleep time: ");
  510.             refresh();
  511.             echo();
  512.             getstr(ibuf);
  513.             noecho();
  514.             if (*ibuf) repeat_time = atoi(ibuf);
  515.             if (repeat_time < 0) repeat_time = 0;
  516.             break;
  517.         case 'w':
  518.             printw("width: ");
  519.             refresh();
  520.             echo();
  521.             getstr(ibuf);
  522.             noecho();
  523.             if (*ibuf) width = atoi(ibuf);
  524.             if (width < MINWIDTH) width = MINWIDTH;
  525.             break;
  526.         case 'n':
  527.             printw("nlines: ");
  528.             refresh();
  529.             echo();
  530.             getstr(ibuf);
  531.             noecho();
  532.             if (*ibuf) nlines = atoi(ibuf);
  533.             if (nlines == 0 || nlines > (LINES-3)) nlines = (LINES-3);
  534.             break;
  535.         case 'k':
  536.             printw("kill ");
  537.             refresh();
  538.             echo();
  539.             getstr(ibuf);
  540.             noecho();
  541.             if (*ibuf) dokill(ibuf);
  542.             break;
  543.         case 'r':
  544.             printw("renice ");
  545.             refresh();
  546.             echo();
  547.             getstr(ibuf);
  548.             noecho();
  549.             if (*ibuf) dorenice(ibuf);
  550.             break;
  551.         case 'p':
  552.             /* toggle ppid_mode */
  553.             ppid_mode ^= 1;
  554.             break;
  555.         case 'h':
  556.         case '?':
  557.             helpline = 1;
  558.             break;
  559.         case 'q': quit();
  560.         default: ;
  561.         }
  562.     }
  563.     }
  564. }
  565.  
  566.  
  567.